package compute

import (
	"gitee.com/amoyx/cloud-provider/pkg/cloud/aliyun/models"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	"github.com/alibabacloud-go/ecs-20140526/v3/client"
	ecs20140526 "github.com/alibabacloud-go/ecs-20140526/v3/client"
	util "github.com/alibabacloud-go/tea-utils/v2/service"
	"github.com/alibabacloud-go/tea/tea"
)

type ECSGreeter interface {
	ECS(region string) ECSInterface
}

type ECSInterface interface {
	CreatePostPaidInstance(args models.ECSRequest) (instanceId string, err error)
	CreatePrePaidInstance(args models.ECSRequest) (instanceId string, err error)
	ModifyInstanceSpec(id string, instanceType string) (err error)
	RebootInstance(id string) (err error)
	ResetInstancePassword(id string, password string) (err error)
	ModifyInstanceVncPassword(id string, password string) (err error)
	QueryInstanceStatus(id string) (result models.ECSResponse, err error)
	DeleteInstance(id string) (err error)
	DescribeInstance(id string) (result models.ECSResponse, err error)
	ListByVpcId(vpcId string) (result []models.ECSResponse, err error)
	ListByName(name string) (result []models.ECSResponse, err error)
	ListAll() (result []models.ECSResponse, err error)
	ListInstanceType() (results []string)
}

type ecs struct {
	config *openapi.Config
	region string
	client *client.Client
}

func newECS(c *Compute, region string) ECSInterface {
	v := &ecs{
		config: c.config,
		region: region,
	}
	v.config.Endpoint = tea.String(string(ECSEndPoint))
	_client, _ := ecs20140526.NewClient(v.config)
	v.client = _client
	return v
}

// CreatePostPaidInstance 创建按量付费实例
func (e *ecs) CreatePostPaidInstance(args models.ECSRequest) (instanceId string, err error) {
	return e.createInstance("PostPaid", args)
}

// CreatePrePaidInstance 创建包年包月实例
func (e *ecs) CreatePrePaidInstance(args models.ECSRequest) (instanceId string, err error) {
	return e.createInstance("PrePaid", args)
}

func (e *ecs) createInstance(chargeType string, args models.ECSRequest) (instanceId string, err error) {
	var datadisks []*ecs20140526.CreateInstanceRequestDataDisk
	for _, d := range args.DataDisk {
		datadisks = append(datadisks, &ecs20140526.CreateInstanceRequestDataDisk{
			Size:     tea.Int32(d.Size),
			Device:   tea.String(d.DeviceMount),
			DiskName: tea.String(d.DiskName),
			Category: tea.String(d.Category),
		})
	}
	systemDisk := &ecs20140526.CreateInstanceRequestSystemDisk{
		Size:     tea.Int32(args.SystemDiskSize),
		Category: tea.String(args.SystemDiskCategory),
	}
	defaultImageId := "centos_7_9_x64_20G_alibase_20230919.vhd"
	if args.ImageId != "" {
		defaultImageId = args.ImageId
	}
	createInstanceRequest := &ecs20140526.CreateInstanceRequest{
		RegionId:           tea.String(e.region),
		ImageId:            tea.String(defaultImageId),
		InstanceType:       tea.String(args.InstanceType),
		InstanceName:       tea.String(args.InstanceName),
		HostName:           tea.String(args.HostName),
		Password:           tea.String(args.Password),
		SystemDisk:         systemDisk,
		Description:        tea.String(args.Description),
		VSwitchId:          tea.String(args.SubnetId),
		InstanceChargeType: tea.String(chargeType),
		DataDisk:           datadisks,
	}
	if chargeType == "PrePaid" {
		createInstanceRequest.InstanceChargeType = tea.String("PrePaid")
		createInstanceRequest.AutoRenew = tea.Bool(true)
		createInstanceRequest.AutoRenewPeriod = tea.Int32(1)
		createInstanceRequest.Period = tea.Int32(args.Period)
		createInstanceRequest.PeriodUnit = tea.String("Month")
	}
	runtime := &util.RuntimeOptions{}
	response, err := e.client.CreateInstanceWithOptions(createInstanceRequest, runtime)
	if err != nil {
		return
	}
	return *response.Body.InstanceId, err
}

// DeleteInstance 删除实例
func (e *ecs) DeleteInstance(id string) (err error) {
	deleteInstanceRequest := &ecs20140526.DeleteInstanceRequest{
		InstanceId: tea.String(id),
	}
	runtime := &util.RuntimeOptions{}
	_, err = e.client.DeleteInstanceWithOptions(deleteInstanceRequest, runtime)
	return
}

// ResetInstancePassword 重置实例密码
func (e *ecs) ResetInstancePassword(id string, password string) (err error) {
	modifyInstanceAttributeRequest := &ecs20140526.ModifyInstanceAttributeRequest{
		Password:   tea.String(password),
		InstanceId: tea.String(id),
	}
	runtime := &util.RuntimeOptions{}
	_, err = e.client.ModifyInstanceAttributeWithOptions(modifyInstanceAttributeRequest, runtime)
	return
}

// ModifyInstanceVncPassword 修改web控制台密码
func (e *ecs) ModifyInstanceVncPassword(id string, password string) (err error) {
	modifyInstanceVncPasswdRequest := &ecs20140526.ModifyInstanceVncPasswdRequest{
		RegionId:    tea.String(e.region),
		VncPassword: tea.String(password),
		InstanceId:  tea.String(id),
	}
	runtime := &util.RuntimeOptions{}
	_, err = e.client.ModifyInstanceVncPasswdWithOptions(modifyInstanceVncPasswdRequest, runtime)
	return
}

// ModifyInstanceSpec 修改实例规格
func (e *ecs) ModifyInstanceSpec(id string, instanceType string) (err error) {
	modifyInstanceSpecRequest := &ecs20140526.ModifyInstanceSpecRequest{
		InstanceId:   tea.String(id),
		InstanceType: tea.String(instanceType),
	}
	runtime := &util.RuntimeOptions{}
	_, err = e.client.ModifyInstanceSpecWithOptions(modifyInstanceSpecRequest, runtime)
	return
}

// RebootInstance 重启实例
func (e *ecs) RebootInstance(id string) (err error) {
	rebootInstanceRequest := &ecs20140526.RebootInstanceRequest{
		ForceStop:  tea.Bool(true),
		InstanceId: tea.String(id),
	}
	runtime := &util.RuntimeOptions{}
	_, err = e.client.RebootInstanceWithOptions(rebootInstanceRequest, runtime)
	return
}

func (e *ecs) ListAll() (result []models.ECSResponse, err error) {
	return e.query("", "", "")
}

func (e *ecs) DescribeInstance(id string) (result models.ECSResponse, err error) {
	list, err := e.query(id, "", "")
	if len(list) > 0 {
		result = list[0]
	}
	return
}

// QueryInstanceStatus 查询实例状态
func (e *ecs) QueryInstanceStatus(id string) (result models.ECSResponse, err error) {
	describeInstanceStatusRequest := &ecs20140526.DescribeInstanceStatusRequest{
		RegionId:   tea.String(e.region),
		InstanceId: []*string{tea.String(id)},
	}
	runtime := &util.RuntimeOptions{}
	response, err := e.client.DescribeInstanceStatusWithOptions(describeInstanceStatusRequest, runtime)
	var list []models.ECSResponse
	for _, val := range response.Body.InstanceStatuses.InstanceStatus {
		list = append(list, models.ECSResponse{
			InstanceId: *val.InstanceId,
			Status:     *val.Status,
		})
	}
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (e *ecs) ListByName(name string) (result []models.ECSResponse, err error) {
	return e.query("", "", name)
}

func (e *ecs) ListByVpcId(vpcId string) (result []models.ECSResponse, err error) {
	return e.query("", vpcId, "")
}

// ListInstanceType 查询实例规格列表
func (e *ecs) ListInstanceType() (results []string) {
	describeInstanceTypesRequest := &ecs20140526.DescribeInstanceTypesRequest{}
	runtime := &util.RuntimeOptions{}
	response, _ := e.client.DescribeInstanceTypesWithOptions(describeInstanceTypesRequest, runtime)
	for _, val := range response.Body.InstanceTypes.InstanceType {
		results = append(results, *val.InstanceTypeId)
	}
	return
}

func (e *ecs) query(id string, vpcId string, name string) (result []models.ECSResponse, err error) {
	describeInstancesRequest := &ecs20140526.DescribeInstancesRequest{
		RegionId: tea.String(e.region),
	}
	if id != "" {
		describeInstancesRequest.InstanceIds = tea.String(id)
	}
	if vpcId != "" {
		describeInstancesRequest.VpcId = tea.String(vpcId)
	}
	if name != "" {
		describeInstancesRequest.InstanceName = tea.String(name)
	}
	runtime := &util.RuntimeOptions{}
	if err = tea.Recover(recover()); err != nil {
		return
	}
	response, err := e.client.DescribeInstancesWithOptions(describeInstancesRequest, runtime)
	for _, val := range response.Body.Instances.Instance {
		var ipaddr []string
		for _, v := range val.VpcAttributes.PrivateIpAddress.IpAddress {
			ipaddr = append(ipaddr, *v)
		}
		var vpcAttribute models.VpcAttribute
		if val.VpcAttributes.NatIpAddress != nil {
			var privateIps []string
			for _, v := range val.VpcAttributes.PrivateIpAddress.IpAddress {
				privateIps = append(privateIps, *v)
			}
			vpcAttribute.NatIpAddress = *val.VpcAttributes.NatIpAddress
			vpcAttribute.PrivateIpAddress = privateIps
			vpcAttribute.VSwitchId = *val.VpcAttributes.VSwitchId
			vpcAttribute.VpcId = *val.VpcAttributes.VpcId
		}

		result = append(result, models.ECSResponse{
			Cpu:                *val.Cpu,
			Memory:             *val.Memory,
			InstanceName:       *val.InstanceName,
			CreationTime:       *val.CreationTime,
			ExpiredTime:        *val.ExpiredTime,
			Description:        *val.Description,
			InstanceId:         *val.InstanceId,
			ZoneId:             *val.ZoneId,
			Status:             *val.Status,
			ImageId:            *val.ImageId,
			InstanceType:       *val.InstanceType,
			InstanceChargeType: *val.InstanceChargeType,
			OSName:             *val.OSName,
			OSType:             *val.OSType,
			StartTime:          *val.StartTime,
			VpcAttribute:       vpcAttribute,
			InnerIpAddress:     ipaddr,
		})
	}
	return
}
